import threading
import logging
from collections import deque
import os
import csv

import globalSettings

from fsm import Fsm
from fsm import CountingInvocationsFsm
from tracePlayer import TracePlayer
from wvongAlgorithm import WvongAlgorithmMessageOrders


def performRandomTest(fsmFilePath, randomVariable, outputFilePath):
    fsm = CountingInvocationsFsm()
    fsm.readFromDot(fsmFilePath)

    inputQueue = deque([])
    inputQueueLock = threading.Lock()
    inputCondition = threading.Condition(inputQueueLock)
    
    player = TracePlayer(inputQueue, inputCondition)
    
    algorithm = WvongAlgorithmMessageOrders(inputQueue, inputCondition, fsm)
    
    player.generateRandomTrace(globalSettings.RANDOM_SEED + randomVariable, globalSettings.NUMBER_OF_MESSAGES, globalSettings.DISTRIBUTION, globalSettings.AVERAGE_INTERVAL, globalSettings.OUTPUT_THRESHOLD)
    
    player.saveMessagesToAlgorithmInputQueue()
    algorithm.start()
    algorithm.join()
    
    if outputFilePath != None:
        reportToFile(outputFilePath, player.messages, algorithm.lastTakenMessageOrders)
        
    reportToConsole(player.messages, algorithm)
    
    return algorithm

def performTraceFileTest(fsmFilePath, traceFile, outputFilePath):
    fsm = Fsm()
    fsm.readFromDot(fsmFilePath)

    inputQueue = deque([])
    inputQueueLock = threading.Lock()
    inputCondition = threading.Condition(inputQueueLock)
    
    player = TracePlayer(inputQueue, inputCondition)
    
    algorithm = WvongAlgorithmMessageOrders(inputQueue, inputCondition, fsm)
    

    player.analyzeTraceFile(traceFile)
    player.saveMessagesToAlgorithmInputQueue()

    algorithm.start()
    algorithm.join()

    reportToConsole(player.messages, algorithm)
    reportToFile(outputFilePath, player.messages, algorithm)
 
def reportToFile(outputFilePath, trace, algorithm):
    f = open(outputFilePath, 'w')
    f.write('Przetestowany slad:\n')
    for message in trace:
        f.write(str(message) + '\n')
    f.write('\n')
    f.write('Ustawienia testera:\n')
    f.write('Czas dla kolejki FROM IUT: ' + str(globalSettings.FROM_IUT_DELTA) +' ms\n')
    f.write('Czas dla kolejki TO IUT: ' + str(globalSettings.TO_IUT_DELTA) +' ms\n')
    f.write('Precyzja testera: ' + str(globalSettings.TIME_QUANT) +' ms\n')
    f.write('Czas trwania symulacji: ' + str(algorithm.totalSimTime) + ' ms\n')
    f.write('\n')
    
    if len(algorithm.inputQueue) != 0 or algorithm.fromIutNumberOfMessages > 0 or algorithm.toIutNumberOfMessages > 0:
        f.write('Tester zakonczyl dzialanie przed czasem w wyniku werdyktu "FAIL"\n')
        f.write('Zawartosc kolejki wejsciowej: ' + str(algorithm.inputQueue) + '\n')
        f.write('Zawartosc kolejki FROM IUT: ' + str(algorithm.fromIutQueue) + '\n')
        f.write('Zawartosc kolejki TO IUT: ' + str(algorithm.toIutQueue) + '\n')
        f.write('\n')
    f.write(str(algorithm))
    f.close()

def reportToConsole(trace, algorithm):
    print 'Przetestowany slad:'
    for message in trace:
        print str(message) + ''
    print ''
    print 'Ustawienia testera:'
    print 'Czas dla kolejki FROM IUT: ' + str(globalSettings.FROM_IUT_DELTA) +' ms'
    print 'Czas dla kolejki TO IUT: ' + str(globalSettings.TO_IUT_DELTA) +' ms'
    print 'Precyzja testera: ' + str(globalSettings.TIME_QUANT) +' ms'
    print 'Czas trwania symulacji: ' + str(algorithm.totalSimTime) + ' ms'
    print ''
    
    if len(algorithm.inputQueue) != 0 or algorithm.fromIutNumberOfMessages > 0 or algorithm.toIutNumberOfMessages > 0:
        print 'Tester zakonczyl dzialanie przed czasem w wyniku werdyktu "FAIL"'
        print 'Zawartosc kolejki wejsciowej: ' + str(algorithm.inputQueue) + ''
        print 'Zawartosc kolejki FROM IUT: ' + str(algorithm.fromIutQueue) + ''
        print 'Zawartosc kolejki TO IUT: ' + str(algorithm.toIutQueue) + ''
        print ''
    print str(algorithm)
    
def testMessageSequence(traceDirectory, fsmPath, filenamePattern):
    filenames = os.listdir(traceDirectory)
    for filename in filenames:
        if filename.find('result') == -1 and filename.find(filenamePattern) != -1:
            filePath = traceDirectory + '/' + filename
            performTraceFileTest(fsmPath, filePath, filePath + '_result')
    

def testSekwencje1():
    testMessageSequence('testy/sekwencje', 'c.fsm', 'seq')
    globalSettings.FROM_IUT_DELTA = 40
    globalSettings.TO_IUT_DELTA = 40
    filePath = 'testy/sekwencje/4_seq_pqp_reorder'
    performTraceFileTest('c.fsm', filePath, filePath + '_result1')
    globalSettings.FROM_IUT_DELTA = 200
    globalSettings.TO_IUT_DELTA = 200
    performTraceFileTest('c.fsm', filePath, filePath + '_result2')
    globalSettings.FROM_IUT_DELTA = 100
    globalSettings.TO_IUT_DELTA = 40
    performTraceFileTest('c.fsm', filePath, filePath + '_result3')
    globalSettings.FROM_IUT_DELTA = 300
    globalSettings.TO_IUT_DELTA = 200
    performTraceFileTest('c.fsm', filePath, filePath + '_result4')
    globalSettings.FROM_IUT_DELTA = 400
    globalSettings.TO_IUT_DELTA = 200
    filePath = 'testy/sekwencje/5_seq_long'
    performTraceFileTest('c.fsm', filePath, filePath + '_result')
    
def testSekwencje2():
    globalSettings.FROM_IUT_DELTA = 10
    globalSettings.TO_IUT_DELTA = 10
    globalSettings.TIME_QUANT = 10
    testMessageSequence('testy/fsm', 'testy/fsm/fsm1', 'fsm1_trace')
    testMessageSequence('testy/fsm', 'testy/fsm/fsm2', 'fsm2_trace')
    testMessageSequence('testy/fsm', 'testy/fsm/fsm3', 'fsm3_trace')
    testMessageSequence('testy/fsm', 'testy/fsm/fsm4', 'fsm4_trace')
    testMessageSequence('testy/fsm', 'testy/fsm/fsm5', 'fsm5_trace_ok')
    
    globalSettings.FROM_IUT_DELTA = 50
    globalSettings.TO_IUT_DELTA = 50
    filePath = 'testy/fsm/fsm5_trace_wrong1'
    performTraceFileTest('testy/fsm/fsm5', filePath, filePath + '_result1')
    
    globalSettings.FROM_IUT_DELTA = 100
    globalSettings.TO_IUT_DELTA = 100
    filePath = 'testy/fsm/fsm5_trace_wrong1'
    performTraceFileTest('testy/fsm/fsm5', filePath, filePath + '_result2')
    
    globalSettings.FROM_IUT_DELTA = 120
    globalSettings.TO_IUT_DELTA = 100
    filePath = 'testy/fsm/fsm5_trace_wrong2'
    performTraceFileTest('testy/fsm/fsm5', filePath, filePath + '_result1')
    
    globalSettings.FROM_IUT_DELTA = 140
    globalSettings.TO_IUT_DELTA = 100
    filePath = 'testy/fsm/fsm5_trace_wrong2'
    performTraceFileTest('testy/fsm/fsm5', filePath, filePath + '_result2')
  
def testLosowosc1():
    
    startQueueSize = 10
    endQueueSize = 230
    stepSize = 10
    numberOfTests = 20
    
    spamWriter = csv.writer(open('wyniki.csv', 'wb'), delimiter=';')
    testColumns = []
    for i in range(numberOfTests):
        testColumns.append("test " + str(i+1))
    columns = ['from iut','to iut', 'time quant', 'number of messages', 'random seed', 'poisson', 'avg interval', 'threshold'] + testColumns + ['srednia'] + ['wywolania nextStates']
    
    spamWriter.writerow(columns)

    averageHeader = [''] + range(startQueueSize, endQueueSize, stepSize)
    averageWriter = csv.writer(open('averages.csv', 'wb'), delimiter=';')
    averageWriter.writerow(averageHeader)
    
    invocationWriter = csv.writer(open('invocations.csv', 'wb'), delimiter=';')
    invocationWriter.writerow(averageHeader)
    
    for fromIut in range(startQueueSize, endQueueSize, stepSize):
        averages = [fromIut]
        invocations = [fromIut]
        
        for toIut in range(startQueueSize, endQueueSize, stepSize):
            print "Test dla", fromIut, toIut
            globalSettings.FROM_IUT_DELTA = fromIut
            globalSettings.TO_IUT_DELTA = toIut
            numbersOfTraces = []
            for i in range(numberOfTests):
                result = performRandomTest('c.fsm', i, None)
                numbersOfTraces.append(len(result.lastTakenMessageOrders))
            columns = [globalSettings.FROM_IUT_DELTA, 
                       globalSettings.TO_IUT_DELTA,
                       globalSettings.TIME_QUANT,
                       globalSettings.NUMBER_OF_MESSAGES,
                       globalSettings.RANDOM_SEED,
                       globalSettings.DISTRIBUTION,
                       globalSettings.AVERAGE_INTERVAL,
                       globalSettings.OUTPUT_THRESHOLD]
            average = sum(numbersOfTraces)/len(numbersOfTraces)
            averages.append(average)
            invocations.append(result.fsm.numberOfNextStatesInvocation)
            columns = columns + numbersOfTraces + [average] + [result.fsm.numberOfNextStatesInvocation]
            spamWriter.writerow(columns)
            
        averageWriter.writerow(averages)
        invocationWriter.writerow(invocations)
    
if __name__ == '__main__':
    logging.basicConfig(level=logging.ERROR) 
    #===========================================================================
    # globalSettings.FROM_IUT_DELTA = 1200
    # globalSettings.TO_IUT_DELTA = 1200
    # tracesTested = []
    # for i in range(20):
    #    result = performRandomTest('c.fsm', i, None)
    #    tracesTested.append(len(result.lastTakenMessageOrders))
    # print tracesTested
    #===========================================================================
    #globalSettings.FROM_IUT_DELTA = 10
    #globalSettings.TO_IUT_DELTA = 10
    #globalSettings.TIME_QUANT = 10
    #testMessageSequence('testy/fsm', 'testy/fsm/fsm4', 'fsm4_trace')

    #testLosowosc1()
    globalSettings.FROM_IUT_DELTA = 60
    globalSettings.TO_IUT_DELTA = 20
    result = performRandomTest('worstCase.fsm', 0, None)
    #reportToConsole([None], result)
    #print "haha", result.fsm.numberOfNextStatesInvocation
    #performTraceFileTest('b.fsm', 'trace.txt', None)
    #===========================================================================
    # tracesTested = []
    # for i in range(1):
    #    result = performRandomTest('b.fsm', i, None)
    #    tracesTested.append(result)
    # #print tracesTested
    # print result
    #===========================================================================
    #performRandomTest('b.fsm', 0, None)             
    print "END"

